
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;

public class RemoteObserver extends UnicastRemoteObject implements RemoteObserverInterface, Subject, Originator {

	/**
	 * 
	 */
	private static final long serialVersionUID = -7104980249749434536L;

	private Document doc;
	private List<Observer> obs;
	private String clientName = null;
	
	RemoteSubjectInterface server;
	
	
	/*
	 * Remote observer part
	 * 
	 */
	protected RemoteObserver(String clientID) throws RemoteException {
		super();
		
		this.obs = new ArrayList<Observer>();
		this.doc = new Document("DefaultName");
		this.setClientName(clientID);
		
		
		// TODO Auto-generated constructor stub
		System.out.println("Client "+clientID+" is now getting subject (server) handle from rmi!");
		
		
			System.setSecurityManager(new RMISecurityManager());
		
		String name = "drawserver";
		
		try {
		   
		    // Get reference to remote object
		    System.out.println("Lookingup name: " + name);
		    this.server = (RemoteSubjectInterface) Naming.lookup(name);
		    
		 
		    
		    if(this.server == null) {
		    	System.out.println("Failed to get server handle");
		    	
		    	return;
		    }
		    
		    System.out.println("Got handle to server object");

		    
		} catch (Exception e) {
		    System.out.println("Client main() exception: " 
				       + e.getMessage());
		    e.printStackTrace();
		}	
		
		
	}
	
	public void attachToServer(String clientID) {
		
		try {
			this.server.Attach(clientID);
			System.out.println(clientID+" is now attached to the server");
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	    
	    	
	
	}
	

	@Override
	public void Update(RemoteSubjectInterface theChangedSubject) throws RemoteException {
		// TODO Auto-generated method stub
		//this.setDoc(theChangedSubject.getDoc());
		
		this.doc = theChangedSubject.getDoc();
		System.out.println("Got document from server with name : "+this.getDoc().name);
		
		Notify();
	}

	
	
	
	
	
	
	
	/*
	 * SubjectPart 
	 * 
	 * 
	 */
	
	public void Attach(Observer obs) {
		this.obs.add(obs);
	}


	public void Detach(Observer obs) {
		this.obs.remove(obs);
	}


	public void Notify() {
		for (Observer obs : this.obs) {
			obs.Update(this);
		}
	}


	public Document getDoc() {
		return this.doc;
	}


	public void setDoc(Document doc) {
		this.doc = doc;
		
		try {
			this.server.setDoc(doc);
			
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	
	/**
	 * Aux func
	 * 
	 * 
	 */
	public void startDoc() {
		
		Document tmp = null;
		try {
			tmp = server.getDoc();
			
			
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		if(tmp == null) {
			
			System.out.println("Server doc empty");
			
			this.doc = new Document(this.getClientName()+"'s Doc");
			
			try {
				server.setDoc(this.doc);
				
				
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			Notify(); //update attached views
			
		} else {
			
			this.doc = tmp;
			System.out.println("Joinned doc "+tmp.name);
			Notify(); //update attached views
		}
		
		
		
	}

	public void exit() {
		// TODO Auto-generated method stub
		try {
			server.Detach(this.getClientName());
			
			
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	@Override
	public Memento CreateMemento() {
		// TODO Auto-generated method stub
		Memento mem = new DocumentMemento();
		mem.SetState(this.doc);
		return mem;
	}

	@Override
	public void SetMemento(Memento mem) {
		// TODO Auto-generated method stub
		this.setDoc((Document)mem.GetState());
		
	}

	public void setClientName(String clientName) {
		this.clientName = clientName;
	}

	public String getClientName() {
		return clientName;
	}
	
	
	

}
